package com.fingard.dsp.bank.directbank.fc11;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.codec.binary.Base64;

import com.fingard.constant.DateFormat2;
import com.fingard.constant.Format;
import com.fingard.dsp.bank.directConfig.FtpSet;
import com.fingard.dsp.bank.directbank.FailCode;
import com.fingard.dsp.bank.directbank.PaymentState;
import com.fingard.dsp.bank.directbank.bankInterface.IBatRecRefund;
import com.fingard.dsp.bank.directbank.fc11.util.JsonUtil;
import com.fingard.dsp.bank.directbank.fc11.util.NFSEpayReqDto;
import com.fingard.dsp.bank.directbank.fc11.util.RSACoder;
import com.fingard.dsp.bank.reqrespobj.batrecrefund.ReqBatRecRefund;
import com.fingard.dsp.bank.reqrespobj.batrecrefund.ReqQryBatRecRefund;
import com.fingard.dsp.bank.reqrespobj.batrecrefund.RetAtsBatRecRefund;
import com.fingard.dsp.bank.reqrespobj.batrecrefund.RetAtsQryBatRecRefund;
import com.fingard.dsp.bank.reqrespobj.batrecrefund.detail.RetAtsBatRecRefundDetail;
import com.fingard.io.FileHelper;
import com.fingard.net.ConnState;
import com.fingard.net.FtpReceiver;
import com.fingard.net.SftpPortClient;
import com.fingard.text.StringHelper;

/**
 * 富聪退保接口
 * 
 * 参考文档：NFS保险统一交互方案V2.4- 渤海.docx
 * 
 * @author fanghh
 * @lastModified 2018/7/26
 */
public class FC11BatRecRefund extends FC11Base implements IBatRecRefund {
	/**
	 * 退保提交
	 * 
	 * 参考接口：2.9  资金划拨文件（Required）
	 * 
	 * 文件命名规则
	 * {instid}_transfer_yyyyMMddHHmm.txt
	 */
	@Override
	public RetAtsBatRecRefund submitBatRecRefund(ReqBatRecRefund p_reqBatRef) throws Exception {
		RetAtsBatRecRefund retAts = new RetAtsBatRecRefund(p_reqBatRef.reqHeader);

		SftpPortClient sftpPortClient = null;
		try {
			// 退保文件内容
			StringBuilder sbFileContent = new StringBuilder();
			
			// 汇总信息：version:1|总笔数:xx
			sbFileContent.append("version:1|总笔数:").append(p_reqBatRef.totalNum).append("\r\n");
			
			// 每笔明细字段标题：资产标识|资金划拨报文|退保申请流水号
			sbFileContent.append("资产标识|资金划拨报文|退保申请流水号\r\n");
			
			// 流水号映射文件内容
			StringBuilder seqNoMappingContent = new StringBuilder();
			while (p_reqBatRef.readRecord()) {
				if (seqNoMappingContent.length() > 0) {
					seqNoMappingContent.append("\r\n");
				}
				
				String payChannelInfo = getBankConfig().getMapValueByKey("payChannelMapping", p_reqBatRef.readedDetail.payChannel);
				String[] payChannelInfoArr = null;
				if (StringHelper.hasAnyChar(payChannelInfo)) {
					payChannelInfoArr = payChannelInfo.split(",");
				} else {
					WriteBankLogLn("缺失'payChannelMapping'配置!");
					retAts.respCode = "0";
					retAts.respInfo = "缺失'payChannelMapping'配置!";
					retAts.reqSeqID = p_reqBatRef.reqBatchNO;
					retAts.transState = PaymentState.FAIL_Batch;
					retAts.payInfoCode = FailCode.E9981;
					retAts.writeRetToATS();
					return retAts;
				}
				
				NFSEpayReqDto nfsEpayReqDto = new NFSEpayReqDto();
				
				nfsEpayReqDto.setVersion(payChannelInfoArr[0]);  
				nfsEpayReqDto.setAction(payChannelInfoArr[1]); // 操作名称
				nfsEpayReqDto.setPlatformId(payChannelInfoArr[2]); // 商户平台ID
				nfsEpayReqDto.setPlatformWithDrawDate(Format.DateTime14Format.format(p_reqBatRef.readedDetail.getPayDateTime())); //商品提现日期
				nfsEpayReqDto.setPlatformWithDrawId(p_reqBatRef.readedDetail.askNumber); // 商品提现流水
				nfsEpayReqDto.setWithDrawAmount(p_reqBatRef.readedDetail.payAmount); // 提现金额
				nfsEpayReqDto.setBankAccountId(generateAES(p_reqBatRef.readedDetail.recAct, payChannelInfoArr[3])); //收款银行账号
				nfsEpayReqDto.setBankAccountName(p_reqBatRef.readedDetail.recName); // 收款银行户名
				nfsEpayReqDto.setCityId("4"); // 收款银行所在市id
				nfsEpayReqDto.setBankId(getBankConfig().getMapValueByKey("bankCodeMapping", p_reqBatRef.readedDetail.recBankCode)); // 收款开户银行id
				nfsEpayReqDto.setCurrencyType("00"); // 货币类型
				
		        String moneyTransferMsg = JsonUtil.writeValue(nfsEpayReqDto);
		        WriteBankLogLn("转换后资金划拨报文json串:\r\n" + moneyTransferMsg);
		        
		        String resultTransferMsg = Base64.encodeBase64String(moneyTransferMsg.getBytes(getCharset("utf-8", "base64"))).trim();
		        WriteBankLogLn("加密后的资金划拨报文:\r\n" + resultTransferMsg);
		        
		        String privateKey = getBankConfig().getValueAsString("privateKey");
		        if (StringHelper.isNullOrEmpty(privateKey)) {
		        	WriteBankLogLn("缺失'privateKey'配置!");
					retAts.respCode = "0";
					retAts.respInfo = "缺失'privateKey'配置!";
					retAts.reqSeqID = p_reqBatRef.reqBatchNO;
					retAts.transState = PaymentState.FAIL_Batch;
					retAts.payInfoCode = FailCode.E9981;
					retAts.writeRetToATS();
					return retAts;
				}
		        
		        String signature = RSACoder.sign(resultTransferMsg.getBytes(getCharset()), privateKey);
		        WriteBankLogLn("加密后资金划拨报文 sign:\r\n" + signature);
		        
		        String singleEncryptMsg = "msg=" + resultTransferMsg + "&msgType=JSON&sign=" + signature;
		        WriteBankLogLn2("单笔资金划拨报文：" + singleEncryptMsg);
		        
		        // 每笔明细：资产标识|资金划拨报文(密文)|退保申请流水号
				String tmpReqBodyDetail = MessageFormat.format("{0}|{1}|{2}\r\n", p_reqBatRef.readedDetail.userId, singleEncryptMsg, p_reqBatRef.readedDetail.refundNo);
				sbFileContent.append(tmpReqBodyDetail);
				
				seqNoMappingContent.append(p_reqBatRef.reqBatchNO).append(",").append(p_reqBatRef.readedDetail.askNumber);
			}
			WriteBankLogLn2("本地退保文件内容:\r\n" + sbFileContent.toString());
			
			// 生成待上传文件并写入内容
			String refundFileDir = getRefundFileDirectory();
			Date tmpDateNow = new Date();
			String refundFileName = bankFront.org + "_transfer_" + new DateFormat2("yyyyMMddHHmm").format(tmpDateNow);
			String localRefundFilePath = refundFileDir + File.separator + refundFileName + ".txt";
			WriteBankLogLn2("本地退保文件路径: " + localRefundFilePath);
			FileHelper.writeFile(localRefundFilePath, sbFileContent.toString(), getCharset());
			
			// 退保流水映射存入本地
			WriteBankLogLn2("本地退保流水映射文件内容:\r\n" + seqNoMappingContent.toString());
			String refundSeqNoPath = getDataFileDirectory(tmpDateNow) + File.separator + Format.Date8Format.format(tmpDateNow) + ".txt";
			WriteBankLogLn2("本地退保流水映射文件路径:" + refundSeqNoPath);
			FileHelper.appendFile(refundSeqNoPath, seqNoMappingContent.toString() + "\r\n", getCharset());
			
			// 上传退保文件
			FtpSet ftpSet = bankFront.getFtpSet("refund_upload");
			sftpPortClient = new SftpPortClient(ftpSet);
			String  directDir = "";
			String tmpDate = Format.Date8Format.format(tmpDateNow);
			if (ftpSet.upDir.endsWith("/")) {
				directDir = tmpDate;
			} else {
				directDir = "/" + tmpDate;
			}
			String sftpFilePath = StringHelper.trimEnd(ftpSet.upDir, "/") + "/" + tmpDate + "/" + refundFileName + ".txt";
			WriteBankLogLn2("SFTP服务器文件上传路径:" + sftpFilePath);
			
			// 判定本地待上传文件和SFTP服务器上传目录是否存在同名文件
			WriteBankLogLn2("重复检测开始...\r\n待检测SFTP服务器目录:" + ftpSet.upDir + directDir);
			FtpReceiver ftpListFileReceiver = sftpPortClient.listFiles(ftpSet.upDir + directDir);
			if (ftpListFileReceiver.isCompleted) {
				WriteBankLogLn2("检测后SFTP服务器目录下文件列表:\r\n" + ftpListFileReceiver.connMsg);
				List<String> fileNameList = Arrays.asList(ftpListFileReceiver.connMsg.split(","));
				Iterator<String> it = fileNameList.iterator();
				String localRefundFileName = refundFileName + ".txt";
				while (it.hasNext()) {
					String sftpFileName = ((String)it.next()).toString();
					if (localRefundFileName.equals(sftpFileName)) {
						retAts.respCode = "0";
						retAts.respInfo = "批次文件已上传，请勿重复上传!";
						retAts.transState = "BatchFailed";
						retAts.payInfoCode = "RepeatUpload";
						retAts.writeRetToATS();
						return retAts;
					}
				}
			} 
			
			WriteBankLogLn2("重复检测成功，可以上传文件!");
			FtpReceiver ftpReceiver = sftpPortClient.uploadFile(directDir, localRefundFilePath, sftpFilePath);

			retAts.respCode = "0";
			retAts.reqSeqID = p_reqBatRef.reqBatchNO;
			if (ftpReceiver.isCompleted) {
				retAts.respInfo = "上传成功";
				retAts.transState = "Uploaded";
				retAts.payInfoCode = "I4001";
			} else if (ConnState.FAIL.equals(ftpReceiver.connState)) {
				retAts.respInfo = "上传通讯失败";
				retAts.transState = "BatchFailed";
				retAts.payInfoCode = "E9999";
			} else {
				retAts.respCode = "-1";
				retAts.respInfo = ftpReceiver.connMsg;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			retAts.respCode = "-1";
			retAts.respInfo = ex.toString();
			WriteBankLogLn(ex);
		}finally{
    		if(sftpPortClient != null){
    			try {
					sftpPortClient.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
					WriteBankLogLn(e);
				}
    		}
    	}

		if ("-1".equals(retAts.respCode) && StringHelper.isNullOrEmpty(retAts.reqSeqID)) {
			retAts.reqSeqID = p_reqBatRef.reqBatchNO;
		}
		
		retAts.writeRetToATS();
		return retAts;
	}

	/**
	 * 退保查询
	 * 
	 * 参考接口：2.10  到账结果文件（Required）
	 * 
	 * 命名规则
	 * {instid}_account_result_yyyyMMddHHmm.txt
	 */
	@Override
	public RetAtsQryBatRecRefund queryBatRecRefund(ReqQryBatRecRefund p_reqQryBatRef) throws Exception {
		RetAtsQryBatRecRefund retAts = new RetAtsQryBatRecRefund(p_reqQryBatRef.reqHeader);
		retAts.reqSeqID = p_reqQryBatRef.reqBatchNO;
		
		SftpPortClient sftpPortClient = null;
		try {
			File refundSeqNoDir = new File(getDataFileDirectory(p_reqQryBatRef.getBgnDateTime()));
			if (refundSeqNoDir.exists()) {
				String refundSeqNoPath = getDataFileDirectory(p_reqQryBatRef.getBgnDateTime()) + File.separator + Format.Date8Format.format(p_reqQryBatRef.getBgnDateTime()) + ".txt";
				WriteBankLogLn2("本地退保流水映射文件路径:" + refundSeqNoPath);
				
				// 1、读取本地退保流水映射文件
				String tmpSeqNoContent = FileHelper.readFileText(refundSeqNoPath, getCharset());
				WriteBankLogLn2("本地退保流水映射文件内容:\r\n" + tmpSeqNoContent);
				if (StringHelper.isNullOrEmpty(tmpSeqNoContent)) {
					retAts.respCode = "-1";
	    			retAts.respInfo = "退保流水映射文件内容为空!";
	    			retAts.writeAfterDetail();
	    			return retAts;
				}
				String[] tmpSeqNoArray = tmpSeqNoContent.split("\r\n");
				
				FtpSet ftpSet = bankFront.getFtpSet("refund_download");
	            String directDir = "";
	            Date tmpDateNow = new Date();
				String tmpDate = Format.Date8Format.format(tmpDateNow);
				if (ftpSet.downDir.endsWith("/")) {
					directDir = tmpDate;
				} else {
					directDir = "/" + tmpDate;
				}
				sftpPortClient = new SftpPortClient(ftpSet);
				
				// 2、读取本地标记文件
				String localTagContent = "";
				File localTagFile = new File(getDataIndexDir(tmpDateNow) + File.separator + tmpDate + ".txt");
				if (localTagFile.exists()) {
					localTagContent = FileHelper.readToString(localTagFile, getCharset());
				}
				
				// 3、查找SFTP下载目录指定文件
				String qryBatRefundFileName = "";
				FtpReceiver ftpListFileReceiver = sftpPortClient.listFiles(ftpSet.downDir + directDir);
				if (!ftpListFileReceiver.isCompleted) {
					retAts.respCode = "-1";
					if (ConnState.FILE_NOT_EXISTS.equals(ftpListFileReceiver.connState)) {
		    			retAts.respInfo = "SFTP服务器批次结果文件尚未生成!";
					} else {
			    		retAts.respInfo = "遍历目录:" + ftpSet.downDir + directDir + "失败!";
					}
		    		retAts.writeAfterDetail();
					return retAts;
				}
				
				List<String> fileNameList = Arrays.asList(ftpListFileReceiver.connMsg.split(","));
				Iterator<String> it = fileNameList.iterator();
				StringBuilder sftpFileContent = new StringBuilder();
				while (it.hasNext()) {
					String sftpFileName = ((String)it.next()).toString();
					if (localTagFile.exists()) {
						// 本地标记文件存在，先遍历获取未处理的文件名(只有一个)
						if (localTagContent.contains(sftpFileName)) {
							continue;
						}
						qryBatRefundFileName = sftpFileName;
					} else {
						// 本地标记文件不存在，读取第一个文件名下载解析即可(只有一个)
						qryBatRefundFileName = sftpFileName;
					}
					
					if (StringHelper.isNullOrEmpty(qryBatRefundFileName)) {
						retAts.respCode = "-1";
						retAts.respInfo = "服务器结果文件均已处理过，无需再次处理!";
			    		retAts.writeAfterDetail();
						return retAts;
					}
					
					// 4、下载退保结果文件至本地
					String localRefundFilePath = createTempFileDirectory() + File.separator + qryBatRefundFileName;
		            WriteBankLogLn2("退保结果文件保存本地路径:" + localRefundFilePath);
		            
					String sftpFilePath = ftpSet.downDir + directDir + "/" + qryBatRefundFileName;
					WriteBankLogLn2("待下载SFTP文件目录路径:" + sftpFilePath);
		            FtpReceiver ftpReceiver = sftpPortClient.downloadFile(directDir, qryBatRefundFileName, localRefundFilePath);
		            
		            if (ftpReceiver.isCompleted) {
		            	sftpFileContent.append(FileHelper.readFileText(localRefundFilePath, getCharset()));
		            	FileHelper.appendFile(localTagFile.getPath(), qryBatRefundFileName + "\r\n", getCharset());
		            } else {
		            	retAts.respCode = "-1";
		    			retAts.respInfo = "退保结果文件下载失败:" + ftpReceiver.connMsg;
		            }
				}
				
				if (sftpFileContent.length() == 0) {
					File[] localRefundFileList = new File(getTempFileDirectory()).listFiles();
					for (File eachRefundFile : localRefundFileList) {
						sftpFileContent.append(FileHelper.readToString(eachRefundFile, getCharset()));
					}
				}
				
				String tmpStrRet = sftpFileContent.toString();
				WriteBankLogLn2("当天SFTP退保结果文件内容:\r\n" + tmpStrRet);
                
            	// 5、解析返回ATS
            	if (StringHelper.hasAnyChar(tmpStrRet)) {
            		retAts.respCode = "0";
					retAts.reqSeqID = p_reqQryBatRef.reqBatchNO;
					
					StringReader strReader = new StringReader(tmpStrRet);
					BufferedReader tmpReader = new BufferedReader(strReader);
					tmpReader.readLine();
					tmpReader.readLine();
					
					while(true) {
						String eachline = tmpReader.readLine();
						if(eachline == null){
							break;
						}
						if (eachline.indexOf("|") > 0) {
							String[] detailNodes = eachline.split("\\|");
							RetAtsBatRecRefundDetail tmpRetDetail = new RetAtsBatRecRefundDetail();
							
							for(String tmpSeqNo : tmpSeqNoArray) {
								if ((tmpSeqNo.length() > 0) && tmpSeqNo.contains(detailNodes[2])) {
									if (tmpSeqNo.split(",")[0].equals(p_reqQryBatRef.reqBatchNO)) {
										tmpRetDetail.askNumber = tmpSeqNo.split(",")[1];
										tmpRetDetail.oriOppOrderNo = detailNodes[3];
										tmpRetDetail.payAmount = detailNodes[4];
										
										// 1: 成功 2:失败
										String transState = detailNodes[5];
										if ("1".equals(transState)) {
											tmpRetDetail.result = PaymentState.SUCCESS;
										} else {
											tmpRetDetail.result = PaymentState.FAIL_Payment;
										}
										
										tmpRetDetail.payInfoCode = detailNodes[6];
										
	    					        	retAts.writeRetDetail(tmpRetDetail);
									}
								}
							}
						}
					}
            	} else {
            		retAts.respCode = "-1";
            		retAts.respInfo = "下载后本地退保结果文件内容为空";
            	}
			} else {
				retAts.respCode = "-1";
				retAts.respInfo = "本地退保流水映射目录不存在，未发生过退保交易!";
			}
		} catch(Exception ex) {
			ex.printStackTrace();
			retAts.respCode = "-1";
			retAts.respInfo = ex.getMessage();
			WriteBankLogLn(ex);
		} finally{
    		if(sftpPortClient != null){
    			try {
					sftpPortClient.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
					WriteBankLogLn(e);
				}
    		}
    	}
		
		if (!"-1".equals(retAts.respCode)) {
			if (retAts.getWrittenRdCount() == 0) {
				retAts.respCode = "-1";
        		retAts.respInfo = "没有符合条件的记录!";
			}
		}
		
		retAts.writeAfterDetail();
		return retAts;
	}
}
